package org.sgx.gwteditors.client.editor;

import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.sgx.gwteditors.client.editor.props.PropertyHaver;
import org.sgx.gwteditors.client.editor.props.PropertyInfo;
import org.sgx.gwteditors.client.util.LWMap;
import org.sgx.gwteditors.client.util.Util;

import com.google.gwt.user.client.Window;

/**
 * a knowledge expert class about types. EditorFramework implementations are responsible of
 * registering its editor classes using this Types class see EditorFramework1.
 * @author sg
 */
public class Types {
	static Logger logger = Logger.getLogger(Types.class+"");
	private static Types instance;

	private LWMap<String, Class<? extends Object>> types;
	/** types reversed */
//	private LWMap<Class<? extends Object>, String> classTypes;
	private LWMap<String, List<EditorCreator>> editors;
	private LWMap<String, EditorCreator> editorNames;
	private Types() {
		types=LWMap.create();
		editors=LWMap.create();
		editorNames=LWMap.create();
//		classTypes=LWMap.create();
	}

	public static Types getInstance() {
		if (null == instance) {
			instance = new Types();
		}
		return instance;
	}
	public LWMap<String, Class<? extends Object>> getTypes() {
		return types;
	}
	public LWMap<String, List<EditorCreator>> getEditors() {
		return editors;
	}
	
	public void registerEditor(String typeName, Class<? extends Object> typeClass, 
			EditorCreator ed) {
		types.put(typeName, typeClass);
		editorNames.put(ed.create().getEditorId(), ed); 
//		classTypes.put(typeClass, typeName);
		if(editors.get(typeName)==null) {
			editors.put(typeName, new LinkedList<EditorCreator>());
		}
		editors.get(typeName).add(ed);
	}
	
	/** 
	 * creates an editor for editing a value of type type
	 * @param type the value type name to be edited
	 * @return
	 * @throws EditorNotFound
	 */
	public Editor newEditor(String type) throws EditorNotFound {
//		logger.log(Level.INFO, "requested editor of type "+type);
		System.out.println("newEditor type: "+type);
		if(editors.get(type)==null||editors.get(type).size()==0)
			throw new EditorNotFound(type);
		else {
//			logger.log(Level.INFO, "requested editor sussessfully of type "+type);
			return editors.get(type).get(0).create();
		}
	}
	public Editor<?> newEditorNamed(String editorName) {
		if(editorNames.get(editorName)!=null)
			return (Editor<?>) editorNames.get(editorName).create(); 
		else
			return null; 
	}
	public Editor<?> newPropertyEditor(PropertyHaver ph, String propName) throws EditorNotFound {
		Editor<?> ed = null; 
		PropertyInfo prop = ph.getProperties().get(propName);
		if(prop!=null && Util.notNull(prop.getEditorId())) {
			ed = newEditorNamed(prop.getEditorId()); 
		}		
		if(prop!=null && prop.getType()!=null && ed==null)
			ed = newEditor(prop.getType());
		
		return ed; 
	}
	

	public boolean isValidEditorName(String editorName) {
		return types.get(editorName)!=null;
	}
	
	public LWMap<String, EditorCreator> getEditorNames() {
		return editorNames;
	}
	
}
